#ifndef _Functors_H_
#define _Functors_H_

/******************************************************************************

Description:
  This file includes various Functors used in reduce operations (reducing 
  Trees and Item Counts) and also for sorting transactions according to
  their support values.

Author: Tayfun Sen
Website: http://blog.tayfunsen.com
 
 *****************************************************************************/


#include <ext/hash_map>
#include <string>
#include "shared.hpp"
#include "Tree.hpp"
#include "ResultTree.hpp"

using namespace __gnu_cxx;

// This functor is used while sorting transactions according to support of its
// items. Uses itemCounts hash_map for comparing.
class SortingFunctor {
    public:
        // Constructor which initializes the count hash.
        SortingFunctor(hash_map<std::string, int> * p) : pCounts(p) {}

        bool const operator()(const std::string & s1, const std::string & s2) {
            // If the counts are equal, one must ensure that there is a reliable
            // and consistent way of ordering items. In this case, 
            // literal/alphabetical ordering is used.
            if ((*pCounts)[s1] != (*pCounts)[s2])
                return ((*pCounts)[s1] > (*pCounts)[s2]);
            else {
                // Else use alphabetical sorting.
                return s1 < s2;
            }
        }

    private:
        hash_map<string, int> * pCounts;

};

// Functor operator for reducing two hash_maps each having local counts. It
// is declared commutative after Functor declarations.
// FIXME fonksiyonun const olmasina gerek var mi? Accessor olmasina yani?
// sanirim yok.
// FIXME: hash_map argumanlari referans olsa daha iyi gibi?
struct reduce_counts {
    hash_map<string, int> operator()(hash_map<string, int> x, hash_map<string, int> y) {
        hash_map<string, int>::iterator it = y.begin();

        for ( ; it != y.end(); it++)
            x[it->first] += it->second;

        return x;
    }
};

// Functor operator for reducing two trees. Will be used to combine two fp-trees
// or fp-tree like constructs such as result trees.
// Counts are added to each other, header tables combined on the go.
// FIXME: Tree argumanlari referans olsa daha iyi gibi?
struct reduce_trees {
    Tree operator()(Tree x, Tree y) {
        clock_t start = clock();
        x.merge(y);
        if (Globals::verbose) {
            cout << "Rank " << Globals::rank << ": reduce_trees merge() -\t"
                 << (clock() - start) / double (CLOCKS_PER_SEC) << " s." << endl;
        }
        return x;
    }
};

// Functor operator for reducing two trees. Will be used to combine two fp-trees
// or fp-tree like constructs such as result trees.
// Counts are added to each other, hash indexes combined on the go.
// FIXME: Tree argumanlari referans olsa daha iyi gibi?
struct reduce_result_trees {
    ResultTree operator()(ResultTree x, ResultTree y) {
        x.merge(y);
        return x;
    }
};

// Tell MPI that reduce operations are commutative so that it runs more 
// efficiently.
namespace boost { namespace mpi {
    template<>
        struct is_commutative<reduce_counts, hash_map<string, int> >
        : mpl::true_ { };
    template<>
        struct is_commutative<reduce_trees, Tree >
        : mpl::true_ { };
    template<>
        struct is_commutative<reduce_result_trees, ResultTree >
        : mpl::true_ { };
} } // end namespace boost::mpi

#endif
